import pickle;
from PyQt4 import QtGui, QtCore;

class TraceEvents(QtCore.QObject):    
    def __init__(self, parent):
        super(TraceEvents, self).__init__();        
        self.parent = parent;
        self.mainWin = parent.mainWin;
        self.graphScene = parent.graphScene;
        self.gView = parent.graphScene.graphView;
        self.graphicsView = self.parent.graphicsView;
        self.sceneRect = self.graphScene.sceneRect();
        self.dataModel = parent.dataContainer.dataModel;
        self.dataView = parent.dataContainer.dataView;
        self.dataContainer = parent.dataContainer;
        self.traceDataPath = "";
        self.bShowActs = True;
        self.bShowTrans = True;
        self.bTrackStates = False;
        self.nDelay = 800;
        self.nPastSt = -1;
        self.nPastAct = -1;
        self.createDockContent();        
                
    def onBtnPlay(self):
        if self.btnPlay.text()=="Play":
            self.trTimer.start();
            self.btnPlay.setText("Pause");
        else:
            self.trTimer.stop();
            self.animTrack.stop();
            self.restoreSceneRect();
            self.btnPlay.setText("Play");
            
    def onBtnStop(self):
        self.btnPlay.setText("Play");
        self.trTimer.stop();
        self.animTrack.stop();
        self.restoreSceneRect();
        self.lbxTrace.setCurrentRow(0);
    
    def onBtnNext(self):
        self.btnPlay.setText("Play");
        self.trTimer.stop();
        self.animTrack.stop();
        self.restoreSceneRect();
        nRow = self.lbxTrace.currentRow();
        self.lbxTrace.setCurrentRow(nRow+1);
        
    def onBtnBack(self):
        self.btnPlay.setText("Play");
        self.trTimer.stop();
        self.animTrack.stop();
        self.restoreSceneRect();
        nRow = self.lbxTrace.currentRow();
        self.lbxTrace.setCurrentRow(nRow-1);
        
    def onLbxTraceSelect(self):
        if self.lbxTrace.currentRow() < 0: return;
        #Set "Normal" Status
        if self.nPastSt > 0: 
            self.gView.setNode_StyleStatus(self.nPastSt, 0);
        if self.nPastAct >= 0 and self.nPastSt > 0: 
            self.gView.setAction_StyleStatus(self.nPastSt, self.nPastAct, 0);
        #Set "Current" Status
        sVal = str(self.lbxTrace.currentItem().data(0).toString());
        nVal = sVal.count("->");
        aVal = sVal.split();
        nCurrentSt = int(aVal[2]);
        if nVal==0: #Current State
            self.gView.setNode_StyleStatus(nCurrentSt, 1);
            if self.bTrackStates:
                self.startPos = self.graphScene.getNode(nCurrentSt).pos();
                self.parent.graphicsView.centerOn(self.startPos.x()+70, self.startPos.y()+70);
#            print nCurrentSt;
        elif nVal==1: #Action
            nAct = int(aVal[5])-1;
            self.nPastAct = nAct;
            self.gView.setAction_StyleStatus(nCurrentSt, nAct, 1);
#            print nCurrentSt, nAct;
        elif nVal==2: #Next State
            #Set Current Action
            nAct = int(aVal[5])-1;
            self.nPastAct = nAct;
            self.gView.setAction_StyleStatus(nCurrentSt, nAct, 1);
            #Load Tables for this Event
            self.loadTables();
            #Play Transition Animation
            nNextSt = int(aVal[8])-1;
            nAnim = QtCore.QEasingCurve.InBounce;
            self.gView.animTrans(nCurrentSt-1, nAct, nNextSt, self.nDelay, nAnim);
            #Play Transition State Tracker
            if self.bTrackStates:
                self.startPos = self.graphScene.getNode(nCurrentSt).pos();
                self.endPos = self.graphScene.getNode(nNextSt+1).pos();
                self.animStateTrack(self.startPos, self.endPos);
#            print nCurrentSt, nAct, nNextSt;
        self.nPastSt = nCurrentSt;
        self.graphScene.updateScene();
        
    def loadTables(self):
        if self.traceDataPath=="": return;
        sEvent = str(self.lbxTrace.currentRow()/3+1);
        sTraceDataPath = self.traceDataPath + "TraceData_" + sEvent + ".dat";
        traceData = pickle.load(open(sTraceDataPath));
#        bSameTrans = list(self.dataModel.stateTrans)==list(traceData[0]);
#        bSameDist = list(self.dataModel.stateDists)==list(traceData[2]);
        self.dataModel.stateTrans = traceData[0];
        stVal = traceData[1];
        self.dataModel.stateDists = traceData[2];
        stQ = traceData[3];
        stPolicy = traceData[4];
        vCol = self.dataModel.nDims + 1;
        pCol = self.dataModel.nDims + 2;
        qCol = self.dataModel.nDims + 3;
        nSt = self.dataModel.nStates;
        nAct = self.dataModel.nActions;
        for i in range(nSt):
            self.dataModel.stInfo[i][vCol] = stVal[i];
            self.dataModel.stInfo[i][pCol] = stPolicy[i];
            for j in range(nAct):
                self.dataModel.stInfo[i][qCol+j] = stQ[i][j];
        self.dataView.gridStInfo.updateGrid();
#        if not bSameDist:
        self.dataView.gridStDists.updateGrid();
#        if not bSameTrans:
        self.dataView.gridStTrans.updateGrid();
        self.graphScene.rebuildAllEdges(self.dataModel.stateTrans);
        self.dataContainer.updateSelectedGraphSettings();
        
    def animStateTrack(self, startPos, endPos):
        startRect = QtCore.QRectF(startPos.x()+75, startPos.y()+75, 1,1);
        endRect = QtCore.QRectF(endPos.x()+75, endPos.y()+75, 1,1);
        self.animTrack = QtCore.QPropertyAnimation(self.graphicsView, "sceneRect");
        self.animTrack.setDuration(self.nDelay);
        self.animTrack.setStartValue(startRect);
        self.animTrack.setEndValue(endRect);
        self.animTrack.setEasingCurve(QtCore.QEasingCurve.OutBounce);        
        self.animTrack.start();
#        QtCore.QObject.connect(self.animTrack, QtCore.SIGNAL("finished()"), 
#                               self.animStateTrackFinished);                               
#    def animStateTrackFinished(self):
#        self.graphicsView.setSceneRect(self.sceneRect);
#        self.graphicsView.centerOn(self.endPos.x()+70, self.endPos.y()+70);
    def restoreSceneRect(self):
        if self.graphicsView.sceneRect() != self.sceneRect:
            self.graphicsView.setSceneRect(self.sceneRect);
        
        
    def updateLbxTrace(self):
        stTrace = self.dataModel.stTraceEvents;
        self.lbxTrace.clear();
        nRow = 0;
        for i in range(len(stTrace)):
            for j in range(3):
                st = str(stTrace[i][0]);
                act = str(stTrace[i][1]);
                stNext = str(stTrace[i][2]);
                if j==0:
                    nRow += 1;
                    sRow = str(nRow) + ". ";
                    self.lbxTrace.addItem(sRow + "State " + st);
                elif j==1 and self.bShowActs:
                    nRow += 1;
                    sRow = str(nRow) + ". ";
                    sItem = sRow + "State " + st + " -> Action " + act;
                    self.lbxTrace.addItem(sItem);
                elif j==2 and self.bShowTrans:
                    nRow += 1;
                    sRow = str(nRow) + ". ";
                    sItem = sRow + "State " + st + " -> Action " + act;
                    sItem += " -> State " + stNext;
                    self.lbxTrace.addItem(sItem);
                    
    def updateDelay(self, nDelay):
        if nDelay==0: return;
        self.nDelay = nDelay;
        self.trTimer.setInterval(nDelay);
    
    def updateTrace(self):
        nRow = self.lbxTrace.currentRow();
        self.lbxTrace.setCurrentRow(nRow+1);
        
    def createDockContent(self):        
        #Push Buttons & ListBox-Trace
        self.btnPlay = QtGui.QPushButton("Play", self.mainWin);
        self.btnStop = QtGui.QPushButton("Stop", self.mainWin);
        self.btnNext = QtGui.QPushButton("Next", self.mainWin);
        self.btnBack = QtGui.QPushButton("Back", self.mainWin);
        self.btnPlay.setMaximumWidth(40);
        self.btnStop.setMaximumWidth(40);
        self.btnNext.setMaximumWidth(40);
        self.btnBack.setMaximumWidth(40);
        self.btnPlay.connect(self.btnPlay, QtCore.SIGNAL("clicked()"), self.onBtnPlay);
        self.btnStop.connect(self.btnStop, QtCore.SIGNAL("clicked()"), self.onBtnStop);
        self.btnNext.connect(self.btnNext, QtCore.SIGNAL("clicked()"), self.onBtnNext);
        self.btnBack.connect(self.btnBack, QtCore.SIGNAL("clicked()"), self.onBtnBack);
        self.lbxTrace = QtGui.QListWidget(self.mainWin);
        self.updateLbxTrace();
        self.lbxTrace.connect(self.lbxTrace, QtCore.SIGNAL("itemSelectionChanged()"), 
                              self.onLbxTraceSelect);
        
        #Timer for Animation
        self.trTimer = QtCore.QTimer(self.mainWin);
        self.trTimer.setInterval(self.nDelay);
        self.trTimer.connect(self.trTimer, QtCore.SIGNAL("timeout()"), self.updateTrace);
        
        #Timer for State Tracking        
#        self.stTimer = QtCore.QTimer(self.mainWin);
#        self.stTimer.setInterval(self.nDelay/100.0);
#        self.stTimer.connect(self.trTimer, QtCore.SIGNAL("timeout()"), self.updateStTrack);
#        self.qLine = QtGui.QGraphicsLineItem
        
        self.gridLayout = QtGui.QGridLayout();
        self.gridLayout.addWidget(self.btnStop, 0,0);
        self.gridLayout.addWidget(self.btnPlay, 0,1);
        self.gridLayout.addWidget(self.btnBack, 0,2);
        self.gridLayout.addWidget(self.btnNext, 0,3);
        self.gridLayout.addWidget(self.lbxTrace, 1,0, 1,4);
        self.qWidget = QtGui.QWidget(self.mainWin);
        self.qWidget.setLayout(self.gridLayout);        
        